
#include "adm.h"
#include "scoreboard.h"

void rp_rstatd_adm(int fd, short event, void *arg)
{
	static char fname[] = "rp_rstatd_adm";
	static char msg[] = "fatal error";
	static Err err;
	static Cmd cmd;
	Worker *pworker;
	Worker *temp;
	FLOG_IN(fname);

	/*	receive the command	*/
	if (!(event & EV_READ))
	{
		rp_log(LOG_NOTICE, fname, "Invalid event type.");
		return;
	}
	memset(&cmd, 0, sizeof(Cmd));
	if (rp_comm_recv(fd, &cmd, sizeof(cmd)) != sizeof(cmd))		// nonblocking recv
	{
		rp_log(LOG_WARNING, fname, "Cannot receive the incoming command.");
		return; 
	}
	
	/*	check the previous command    */
	switch (global.code)
	{
		case (OP_SHUTDOWN_FORCE) : {
			rp_log(LOG_WARNING, fname, "Forceful shutdown does not complete immediately!");
			return;			
		}
		case (OP_SHUTDOWN) : {
			if (cmd.code != OP_SHUTDOWN_FORCE)
			{
				rp_log(LOG_WARNING, fname, "Shutdown in process, ignore all pending commands.");
				return;				
			}
			break;
		}
		default : {	/* do nothing */	}
	}

	/*	process the new command	*/
	switch (cmd.code)
	{
		case (OP_REPLICA) : {
			// TODO: we need some mechanism to check rpcopy status
			rp_pid_t pid = rp_process_create("rpcopy", cmd.arg, NULL);
			if (pid < 0) rp_log(LOG_CRITICAL, fname, "Failed to execute rpcopy");
			break;
		}
		case (OP_SHUTDOWN) : {
			global.code = OP_SHUTDOWN;
			err = write(global.fd_pod[1], &global.code, sizeof(OpCode));		
			break;
		}
		case (OP_SHUTDOWN_FORCE) : {
			/*	mark the exit state & save the pworker onto ptable   */
			global.code = OP_SHUTDOWN_FORCE;
			pworker = rp_rstatd_scoreboard_remove_total(&global.sb_live);
			while (pworker) 
			{
				err = rp_process_terminate(pworker->pid, SIGTERM);		// Forceful kill
				rp_log(LOG_WARNING, fname, "Forcefully terminate rpointd, PID = %d");
				/*	remove the worker from scoreboard   */			
				/*	unmap & close the file   */
				err = rp_score_finalize(&(pworker->score));
				if (!munmap((void*)pworker->score, sizeof(Score)))
				{
					rp_log(LOG_CRITICAL, fname, "Cannot unmap the file under /tmp/rally");
				}  else {
					free(temp->score);
				}
				temp = pworker;
				pworker = pworker->next;
				free(temp);				
			}
			
			/*	No running rpointd	  */	
			struct timeval time;
			time.tv_sec = 0;
			time.tv_usec = 0;
			event_base_loopexit(global.evb_server, &time);						
			break;		// rstatd will shutdown at the next timeout
		}
		case (OP_PAUSE): {
			break;
		}
		case (OP_RESUME): {
			break;
		}
		case (OP_NONE) : {
			rp_log(LOG_WARNING, fname, "Are you kidding me?");
			break;
		}
		default: {
			rp_log(LOG_WARNING, fname, "Invalid command");
			break;	
		}
	}
	FLOG_OUT(fname);
	return;
}

